/*
* Nocturne
* Copyright (c) 2015-2016, Lapis <https://github.com/LapisBlue>
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package blue.lapis.nocturne;
import blue.lapis.nocturne.gui.io.mappings.MappingsSaveDialogHelper;
import blue.lapis.nocturne.gui.scene.control.WebLink;
import blue.lapis.nocturne.jar.model.ClassSet;
import blue.lapis.nocturne.mapping.MappingContext;
import blue.lapis.nocturne.mapping.io.writer.MappingWriterType;
import blue.lapis.nocturne.util.helper.PropertiesHelper;
import blue.lapis.nocturne.util.helper.SceneHelper;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Path;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.logging.ConsoleHandler;
import java.util.logging.Logger;
public class Main extends Application {
public final boolean testingEnv;
private static Main instance;
private static final EventHandler<WindowEvent> CLOSE_HANDLER = event -> {
try {
if (MappingsSaveDialogHelper.doDirtyConfirmation()) {
event.consume();
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
};
private static final Logger LOGGER = Logger.getLogger("Nocturne");
private static final Logger FERNFLOWER_LOGGER = Logger.getLogger("FernFlower");
private PropertiesHelper propertiesHelper;
private String locale; // reassigned on reload
private ResourceBundle resourceBundle; // reassigned on reload
private Stage mainStage;
private Scene scene;
private final MappingContext mappingContext = new MappingContext();
private Path currentMappingsPath;
private MappingWriterType currentWriterType;
private ClassSet loadedJar;
static {
LOGGER.setUseParentHandlers(false);
LOGGER.addHandler(new ConsoleHandler() {
@Override
protected void setOutputStream(OutputStream out) throws SecurityException {
super.setOutputStream(System.out);
}
});
}
public static void main(String[] args) {
launch(args);
}
public Main(boolean testingEnv) {
super();
instance = this;
if (!testingEnv) {
initialize();
}
this.testingEnv = testingEnv;
}
public Main() {
this(false);
}
public static Logger getLogger() {
return LOGGER;
}
public static Logger getFernFlowerLogger() {
return FERNFLOWER_LOGGER;
}
public void initialize() {
propertiesHelper = new PropertiesHelper();
locale = getPropertiesHelper().getProperty(PropertiesHelper.Key.LOCALE);
initLocale();
}
public void initLocale() {
try {
resourceBundle = ResourceBundle.getBundle("lang." + locale);
} catch (MissingResourceException ex) {
if (locale.equals("en_US")) {
Main.getLogger().severe("Cannot locate default locale (" + locale + ") - giving up");
throw ex;
}
Main.getLogger().warning("Current locale (" + locale + ") is not available - resetting to en_US");
locale = "en_US";
initLocale();
}
}
@Override
public void start(Stage primaryStage) throws Exception {
mainStage = primaryStage;
String[] icons = new String[] {
"icon-16", "icon-24", "icon-32", "icon-48",
"icon-64", "icon-128", "icon-256", "icon-512"
};
for (String icon : icons) {
mainStage.getIcons().add(new Image(getClass().getResourceAsStream("/img/icons/" + icon + ".png")));
}
loadView(locale);
Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> {
throwable.printStackTrace();
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle(resourceBundle.getString("exception.title"));
alert.setHeaderText(resourceBundle.getString("exception.header"));
TextFlow description = new TextFlow(
new Text(resourceBundle.getString("exception.dialog1") + "\n"),
new Text(resourceBundle.getString("exception.dialog2") + "\n\n"),
new Text(resourceBundle.getString("exception.dialog3")),
new Text(" "),
new WebLink("https://github.com/LapisBlue/Nocturne/issues"),
new Text("\n\n"),
new Text(resourceBundle.getString("exception.dialog4"))
);
description.setLayoutX(20);
description.setLayoutY(25);
TextArea exceptionText = new TextArea();
StringWriter exceptionWriter = new StringWriter();
throwable.printStackTrace(new PrintWriter(exceptionWriter));
exceptionText.setText(exceptionWriter.toString());
exceptionText.setLayoutX(20);
exceptionText.setLayoutY(140);
Pane contentPane = new Pane(description, exceptionText);
alert.getDialogPane().setContent(contentPane);
alert.getButtonTypes().setAll(ButtonType.OK, ButtonType.CLOSE);
alert.showAndWait();
if (alert.getResult() == ButtonType.CLOSE) {
System.exit(0);
}
});
}
public static Main getInstance() {
return instance;
}
public void loadView(String lang) throws IOException {
locale = lang;
resourceBundle = ResourceBundle.getBundle("lang." + lang);
FXMLLoader loader = new FXMLLoader(ClassLoader.getSystemResource("fxml/main.fxml"));
loader.setResources(resourceBundle);
Parent root = loader.load();
if (scene == null) {
scene = new Scene(root);
SceneHelper.addStdStylesheet(scene);
mainStage.setTitle("Nocturne");
mainStage.setScene(scene);
mainStage.setOnCloseRequest(CLOSE_HANDLER);
mainStage.show();
} else {
scene.setRoot(root);
}
}
public static PropertiesHelper getPropertiesHelper() {
return getInstance().propertiesHelper;
}
public static String getCurrentLocale() {
return getInstance().locale;
}
public static ResourceBundle getResourceBundle() {
return getInstance().resourceBundle;
}
public static Stage getMainStage() {
return getInstance().mainStage;
}
public static MappingContext getMappingContext() {
return getInstance().mappingContext;
}
public static Path getCurrentMappingsPath() {
return getInstance().currentMappingsPath;
}
public static void setCurrentMappingsPath(Path path) {
getInstance().currentMappingsPath = path;
}
public static MappingWriterType getCurrentWriterType() {
return getInstance().currentWriterType;
}
public static void setCurrentWriterType(MappingWriterType currentWriterType) {
getInstance().currentWriterType = currentWriterType;
}
public static ClassSet getLoadedJar() {
return getInstance().loadedJar;
}
public static void setLoadedJar(ClassSet classSet) {
getInstance().loadedJar = classSet;
updateTitle();
}
public static void updateTitle() {
if (getInstance().testingEnv) {
return;
}
String title;
if (getLoadedJar() == null) {
title = "Nocturne";
} else {
title = "Nocturne - " + (getMappingContext().isDirty() ? "*" : "") + getLoadedJar().getName();
}
if (!getMainStage().getTitle().equals(title)) {
getMainStage().setTitle(title);
}
}
}